﻿/*
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * See product pages for more information.
 * http://closesudoku.codeplex.com
 * Copyright (C), 2010, hrondra
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Close.Properties;
using System.Xml;
using System.IO;
using Close.controls.MenuPanels;

namespace Close.Data
{
    public enum GameStates : byte { NotPlayed = 1, InProgess, Completed };

    class GameDatabase
    {
        private static readonly GameDatabase _data = new GameDatabase();
        /// <summary>
        /// Bytes for one game
        /// </summary>
        /// <remarks>2-36-162-8-8-1</remarks>
        private const int lineLength = 217;

        /// <summary>
        /// Singleton - game data.
        /// </summary>
        public static GameDatabase GamesData
        {
            get
            {
                return _data;
            }
        }

        private GameData gameData;
        private GameDatabase()
        {
            gameData = new GameData();
            gameData.Level.AddLevelRow(1, Resources.DifEasy);
            gameData.Level.AddLevelRow(2, Resources.DifMedium);
            gameData.Level.AddLevelRow(3, Resources.DifHard);

            gameData.Imprinted.AddImprintedRow("052006000160900004049803620400000800083201590001000002097305240200009056000100970", 1, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("052400100100002030000813025400007010683000597070500002890365000010700006006004970", 2, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("302000089068052734009000000400007000083201590000500002000000200214780350530000908", 3, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("402000007000080420050302006090030050503060708070010060900406030015070000200000809", 4, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("060091080109680405050040106600000200023904710004000003907020030305079602040150070", 5, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("060090380009080405050300106001008200020904010004200900907006030305070600046050070", 6, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("402000380109607400008300106090030004023964710800010060907006500005809602046000809", 7, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("400091000009007425058340190691000000003964700000000963087026530315800600000150009", 8, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("380001004002600070000487003000040239201000406495060000600854000070006800800700092", 9, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("007520060002009008006407000768005009031000450400300781000804300100200800050013600", 10, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("380000000540009078000407503000145209000908000405362000609804000170200045000000092", 11, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("007001000540609078900487000760100230230000056095002081000854007170206045000700600", 12, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("007021900502009078006407500000140039031908450490062000009804300170200805004710600", 13, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("086500204407008090350009000009080601010000080608090300000200076030800409105004820", 14, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("086507000007360100000000068249003050500000007070100342890000000002056400000904820", 15, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("000007230420368000050029768000080650000602000078090000894230070000856019065900000", 16, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("906000200400368190350400000209080051013040980670090302000001076032856009005000803", 17, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("095002000700804001810076500476000302000000000301000857003290075500307006000400130", 18, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("005002740002850901810000500070501302008723600301609050003000075509017200087400100", 19, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("605102740732004001000000020400501300008020600001609007060000000500300286087405109", 20, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("695102040700800000000970023076000090900020004020000850160098000000007006080405139", 21, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("090002748000004901800906500470500090008000600020009057003208005509300000287400030", 22, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("001009048089070030003106005390000500058602170007000094900708300030040860870300400", 23, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("600039708000004600000100025002017506408000103107850200910008000005900000806320009", 24, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("620500700500270631040100005302000086000090000160000204900008050235041007006005019", 25, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("080130002140902007273080000000070206007203900502040000000060318600308024400021050", 26, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("980100402046950000200684001010009086007000900590800070700465008000098720408001059", 27, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("085100400000950007073684001010070080067203940090040070700465310600098000008001650", 28, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("085100460146000807070004001300009080067000940090800003700400010601000724038001650", 29, gameData.Level.FindBylid(1));
            gameData.Imprinted.AddImprintedRow("085130462006000007270680090000009200060213040002800000020065018600000700438021650", 30, gameData.Level.FindBylid(1));
            //medium
            gameData.Imprinted.AddImprintedRow("916004072800620050500008930060000200000207000005000090097800003080076009450100687", 31, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000900082063001409908000000000670300046050290007023000000000701704300620630007000", 32, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("035670000400829500080003060020005807800206005301700020040900070002487006000052490", 33, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("030070902470009000009003060024000837007000100351000620040900200000400056708050090", 34, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("084200000930840000057000000600401700400070002005602009000000980000028047000003210", 35, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("007861000008003000560090010100070085000345000630010007050020098000600500000537100", 36, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("040001003000050079560002804100270080082000960030018007306100098470080000800500040", 37, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000500006000870302270300081000034900793050614008790000920003057506087000300005000", 38, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000900067090000208460078000320094070700603002010780043000850016501000090670009000", 39, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("024000017000301000300000965201000650000637000093000708539000001000502000840000570", 40, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("200006143004000600607008029100800200003090800005003001830500902006000400942600005", 41, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("504002030900073008670000020000030780005709200047060000050000014100450009060300502", 42, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("580000637000000000603540000090104705010709040807205090000026304000000000468000072", 43, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000010000900003408670500021000130780015000240047065000750006014102400009000090000", 44, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("780300050956000000002065001003400570600000003025008100200590800000000417030004025", 45, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("200367500500800060300450700090530400080000070003074050001026005030005007002783001", 46, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("801056200000002381900003000350470000008000100000068037000600002687100000004530806", 47, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("300004005841753060000010000003000087098107540750000100000070000030281796200300008", 48, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000064810040050062009010300003040607008107500704030100006070200430080090017390000", 49, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000040320000357080000600400357006040600705003080900675008009000090581000064070000", 50, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("905040026026050900030600050350000009009020800100000075010009030003080760560070108", 51, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("010403060030017400200000300070080004092354780500070030003000005008530040050906020", 52, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("605900100000100073071300005009010004046293510700040600200001730160002000008009401", 53, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("049060002800210490100040000000035084008102300630470000000080001084051006700020950", 54, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("067020300003700000920103000402035060300000002010240903000508039000009200008010750", 55, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("050842001004000900800050040600400019007506800430009002080090006001000400500681090", 56, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000076189000002030009813000025000010083000590070000460000365200010700000536120000", 57, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("080000030400368000350409700000003650003000900078100000004201076000856009060000020", 58, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("000500748589000001700086900302010580000000000067050204004760002200000867876005000", 59, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("021009008000004031740100025000007086058000170160800000910008052230900000800300410", 60, gameData.Level.FindBylid(2));
            //hard
            gameData.Imprinted.AddImprintedRow("600300100071620000805001000500870901009000600407069008000200807000086410008003002", 61, gameData.Level.FindBylid(2));
            gameData.Imprinted.AddImprintedRow("906013008058000090030000010060800920003409100049006030090000080010000670400960301", 62, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("300060250000500103005210486000380500030000040002045000413052700807004000056070004", 63, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("060001907100007230080000406018002004070040090900100780607000040051600009809300020", 64, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("600300208400185000000000450000070835030508020958010000069000000000631002304009006", 65, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("400030090200001600760800001500318000032000510000592008900003045001700006040020003", 66, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("004090170900070002007204000043000050798406213060000890000709400600040001085030700", 67, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("680001003007004000000820000870009204040302080203400096000036000000500400700200065", 68, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("000002000103400005200050401340005090807000304090300017605030009400008702000100000", 69, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("050702003073480005000050400040000200027090350006000010005030000400068730700109060", 70, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("500080020007502801002900040024000308000324000306000470090006700703208900060090005", 71, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("108090000200308096090000400406009030010205060080600201001000040360904007000060305", 72, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("010008570607050009052170000001003706070000040803700900000017260100020407024300090", 73, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("020439800080000001003001520050092703000000000309740080071300900600000030008924010", 74, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("000500201800006005005207080017960804000000000908074610080405300700600009504009000", 75, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("920000000500870000038091000052930160090000030073064980000410250000053001000000073", 76, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("590006010001254709000001400003715008100000004200648100002500000708463900050100047", 77, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("309870004000005008870400000104580003000706000700034105000009081900300000400057206", 78, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("800200000910300706000007002084000009095104860100000230500600000609003071000005008", 79, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("005037001000050627600002530020070000001968200000010090013700008486090000700840100", 80, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("090350700000800029000402008710000000463508297000000051300204000940005000008037040", 81, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("000005904080090605006000030030701450008040700074206090060000300801060070309800000", 82, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("030004087948700500060800009010586720000000000087312050800003070003007865570200090", 83, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("300687015000030082050000300400300000601050709000004003008000020210040000970521004", 84, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("702000004030702010400093008000827090007030800080956000300570009020309080600000503", 85, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("300040057400853060025700000000000430800406001034000000000005690090624003160080002", 86, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("000260050000005900000380046020094018004000500950810070380021000005700000040058000", 87, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("062080504008050090700320001000740620000203000027065000200036007040070100803090240", 88, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("002001000068000003000086090900002086804000102520800009080140000100000920000700500", 89, gameData.Level.FindBylid(3));
            gameData.Imprinted.AddImprintedRow("000030065460950200000086004003070006004090100500010300200140000007065028630020000", 90, gameData.Level.FindBylid(3));
        }

        public byte GetImprintedValue(ushort gid, int radek, int sloupec)
        {
            return gameData.Imprinted.getvalue(gid, radek, sloupec);
        }

        public class LevelsDataItem
        {
            string title;
            int levelId;

            public LevelsDataItem(string itemTitle, int itemLevelId)
            {
                title = itemTitle;
                levelId = itemLevelId;
            }
        }

        /// <summary>
        /// Return difficulty levels.
        /// </summary>
        public List<string> GetLevels()
        {
            List<string> returnValue = new List<string>(gameData.Level.Count);

            foreach (Data.GameData.LevelRow item in gameData.Level.Rows)
            {
                returnValue.Add(item.title);
            }
            return returnValue;
        }

        /// <summary>
        /// Game for each level.
        /// </summary>
        public List<GameDetail> GetGamesInLevel(int level)
        {
            List<GameDetail> returnValue = new List<GameDetail>(gameData.Imprinted.Count);            
            foreach (Data.GameData.ImprintedRow item in gameData.Imprinted.Select("lid = " + level.ToString()))
            {
                GameData.SavedGameRow sgr = LoadValues(item.gid);
                if (sgr != null)
                {
                    returnValue.Add(new GameDetail(item.gid, sgr.playedtime, sgr.last_played, sgr.state));
                }
                /*never played*/
                else
                {
                    returnValue.Add(new GameDetail(item.gid, 0, DateTime.MinValue, (byte)GameStates.NotPlayed));
                }
            }
            return returnValue;
        }


                /// <summary>
        /// Save values to memory and file.
        /// </summary>
        public void SaveGame(ushort gameId, string values, Int16[] notes, double elapsedTime)
        {
            SaveGame(gameId, values, notes, elapsedTime, GameStates.InProgess);
        }

        /// <summary>
        /// Save values to memory and file.
        /// </summary>
        public void SaveGame(ushort gameId, string values, Int16[] notes, double elapsedTime, GameStates currentState)
        {
            byte[] nts = new byte[162];
            for (int ijk = 0; ijk < 81; ijk++)
            {
                BitConverter.GetBytes(notes[ijk]).CopyTo(nts, ijk * 2);
            }

            DateTime now = DateTime.Now;
            GameStates state = currentState;

            GameData.SavedGameRow savedGameDataRow = gameData.SavedGame.FindBygid(gameId);
            if (savedGameDataRow != null)
            {
                savedGameDataRow.values = values;
                savedGameDataRow.SetNotes(notes);
                savedGameDataRow.playedtime = elapsedTime;
                savedGameDataRow.state = (byte)state;
                savedGameDataRow.last_played = now;
            }
            else
                gameData.SavedGame.AddSavedGameRow(gameData.Imprinted.FindBygid(gameId), values, elapsedTime, nts, now, (byte)state);
            SaveValuesToFile(gameId, values, notes, elapsedTime, now, state);

        }

        /// <summary>
        /// Open file with saved game - find (and replace/ create) game line.
        /// </summary>
        /// <param name="gameId">game id</param>
        /// <param name="values">filled values</param>
        /// <param name="notes">filled notes</param>
        /// <param name="elapsedTime"></param>
        private void SaveValuesToFile(ushort gameId, string values, Int16[] notes, double elapsedTime, DateTime lastPlayed, GameStates state)
        {
            String full_path = System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase;
            String directory_path = full_path.Substring(0, full_path.LastIndexOf("\\"));
            String pth = Path.Combine(directory_path, "Settings\\userdata.bin");

            using (FileStream strm = new FileStream(pth, FileMode.OpenOrCreate, FileAccess.ReadWrite))
            {
                byte[] bytes = new byte[lineLength];
                long numBytesToRead = strm.Length;
                int numBytesRead = 0;
                bool itemFindInFileAndSaved = false;
                while (numBytesToRead > 0)
                {
                    int n = strm.Read(bytes, 0, lineLength);
                    // Break when the end of the file is reached.
                    if (n == 0)
                        break;
                    GameLine line = new GameLine(bytes);
                    if (line.GameId == gameId)
                    {
                        strm.Seek(-lineLength, SeekOrigin.Current);
                        GameLine lineToSave = new GameLine(gameId, values, notes, elapsedTime, lastPlayed, state);
                        strm.Write(lineToSave.GetLineInBytes(), 0, lineLength);
                        itemFindInFileAndSaved = true;
                        break;
                    }
                    numBytesRead += n;
                    numBytesToRead = numBytesToRead - lineLength;
                }
                if (!itemFindInFileAndSaved)
                {
                    GameLine lineToSave = new GameLine(gameId, values, notes, elapsedTime, lastPlayed, state);
                    strm.Write(lineToSave.GetLineInBytes(), 0, lineLength);
                }
            }
        }

        /// <summary>
        /// Load game values - from memory or from file.
        /// </summary>
        /// <param name="gameId">game id</param>
        public GameData.SavedGameRow LoadValues(ushort gameId)
        {
            GameData.SavedGameRow savedGameDataRow = gameData.SavedGame.FindBygid(gameId);
            if (savedGameDataRow != null)
                return savedGameDataRow;
            else
                return LoadValuesFromFile(gameId);
        }

        /// <summary>
        /// Try to load the game data from file.
        /// </summary>
        /// <param name="gameId">game id</param>
        /// <returns>null when the game has not been saved yet</returns>
        private Close.Data.GameData.SavedGameRow LoadValuesFromFile(ushort gameId)
        {
            String full_path = System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase;
            String directory_path = full_path.Substring(0, full_path.LastIndexOf("\\"));
            String pthSettings = Path.Combine(directory_path, "Settings");
            if (!Directory.Exists(pthSettings))
            {
                //should exist because of configuration file, but for sure
                Directory.CreateDirectory(pthSettings);
            }
            String pth = Path.Combine(pthSettings, "userdata.bin");
            using (FileStream strm = new FileStream(pth, FileMode.OpenOrCreate, FileAccess.Read))
            {
                byte[] bytes = new byte[lineLength];
                int numBytesToRead = (int)strm.Length;
                while (numBytesToRead > 0)
                {
                    // Read may return anything from 0 to numBytesToRead.
                    int n = strm.Read(bytes, 0, lineLength);
                    // Break when the end of the file is reached.
                    if (n == 0)
                        break;
                    GameLine line = new GameLine(bytes);
                    if (line.GameId == gameId) //game found
                    {
                        gameData.SavedGame.AddSavedGameRow(gameData.Imprinted.FindBygid(gameId), line.Values, line.ElapsedTime, line.AllNotes, line.LastPlayed, line.GameState);
                        return gameData.SavedGame.FindBygid(gameId);
                    }                    
                }
            }
            return null;
        }

        #region "helpers"

        /// <summary>
        /// Helper class for manipulation with line (one game) from file.
        /// </summary>
        private class GameLine
        {
            private ushort _gameId = 0;
            public int GameId
            {
                get { return _gameId; }
            }
            private byte[] _values = new byte[81];
            /// <summary>
            /// All filled values.
            /// </summary>
            public string Values
            {
                get
                {
                    System.Text.ASCIIEncoding encoding = new ASCIIEncoding();

                    StringBuilder returnValue = new StringBuilder(81);
                    byte[] byteValue = new byte[4];
                    for (int ijk = 0; ijk < 9; ijk++)
                    {
                        uint number = BitConverter.ToUInt32(_values, ijk * 4);                        
                        returnValue.Append(number.ToString().PadLeft(9, '0'));
                    }

                    return returnValue.ToString();
                }
            }
            private Int16[] _allNotesInInt = new Int16[81];
            /// <summary>
            /// All notes in byte array (every note is two bytes - every bit is one number)
            /// </summary>
            public byte[] AllNotes
            {
                get
                {
                    byte[] returnValue = new byte[162];
                    for (int ijk = 0; ijk < 81; ijk++)
                    {
                        BitConverter.GetBytes(_allNotesInInt[ijk]).CopyTo(returnValue, ijk * 2);
                    }
                    return returnValue;
                }
            }
            private double _elapsedTime = 0;
            /// <summary>
            /// Time
            /// </summary>
            public double ElapsedTime
            {
                get { return _elapsedTime; }
            }

            private GameStates _gameState = GameStates.NotPlayed;
            public Byte GameState
            {
                get { return (byte)_gameState; }
            }

            private DateTime _lastPlayed;
            public DateTime LastPlayed
            {
                get { return _lastPlayed; }
            }


            /// <summary>
            /// Create object from file line.
            /// </summary>
            /// <param name="line">bytes in one line (2-36-162-8)</param>
            public GameLine(byte[] line)
            {
                if (line.Length != lineLength)
                    throw new ApplicationException("Incorrect data loaded");
                _gameId = BitConverter.ToUInt16(line, 0);
                for (int ijk = 0; ijk < 81; ijk++)
                {
                    _values[ijk] = line[2 + ijk];
                    _allNotesInInt[ijk] = BitConverter.ToInt16(line, 38 + ijk * 2);
                }
                _elapsedTime = BitConverter.ToDouble(line, 200);
                _lastPlayed = new DateTime(BitConverter.ToInt64(line, 208));
                _gameState = (GameStates)line[216];

            }
            /// <summary>
            /// Create object from items.
            /// </summary>
            /// <param name="gameId">game id</param>
            /// <param name="values">values</param>
            /// <param name="notes">notes</param>
            /// <param name="elapsedTime">time</param>
            public GameLine(ushort gameId, string values, Int16[] notes, double elapsedTime, DateTime lastPlayed, GameStates state)
            {
                _gameId = gameId;
                byte[] concat = new byte[36];
                for (int i = 0; i < 9; i++)
                {
                    System.Buffer.BlockCopy(BitConverter.GetBytes(UInt32.Parse(values.Substring(i * 9, 9))), 0, concat, i * 4, 4);
                }
                _values = concat;
                _allNotesInInt = notes;
                _elapsedTime = elapsedTime;
                _lastPlayed = lastPlayed;
                _gameState = state;
            }

            /// <summary>
            /// Get bytes about the game
            /// </summary>
            /// <returns>Byte presentation of the game</returns>
            public byte[] GetLineInBytes()
            {
                MemoryStream ms = new MemoryStream();
                BinaryWriter binWriter = new BinaryWriter(ms);
                binWriter.Write(_gameId);
                binWriter.Write(_values);
                for (int i = 0; i < 81; i++)
                {
                    binWriter.Write(_allNotesInInt[i]);
                }
                binWriter.Write(_elapsedTime);
                binWriter.Write(_lastPlayed.Ticks);
                binWriter.Write((byte)_gameState);
                ms.Close();
                return ms.ToArray();
            }
        }
        #endregion
    }
}
